﻿using System;

namespace ch11.interpreter
{
    public struct OperandStack
    {
        internal ulong[] Slots;

        internal int StackSize()
        {
            return Slots.Length;
        }

        internal ulong GetOperand(uint idx)
        {
            return Slots[idx];
        }

        public void SetOperand(uint idx, ulong val)
        {
            Slots[idx] = val;
        }

        public void PushU64S(ulong[] vals)
        {
            Array.Resize(ref Slots, Slots.Length + vals.Length);
            for (var i = 0; i < vals.Length; i++)
            {
                Slots[Slots.Length - 1 + i] = vals[i];
            }
        }

        internal ulong[] PopU64S(int n)
        {
            var vals = Slots[^n..];
            Slots = Slots[..^n];
            return vals;
        }

        internal void PushU64(ulong val)
        {
            Array.Resize(ref Slots, Slots.Length + 1);
            Slots[^1] = val;
        }

        internal ulong PopU64()
        {
            var val = Slots[^1];
            Slots = Slots[..^1];
            return val;
        }

        public void PushS64(long val)
        {
            PushU64((ulong) val);
        }

        internal long PopS64()
        {
            return (long) PopU64();
        }

        internal void PushU32(uint val)
        {
            PushU64(val);
        }

        internal uint PopU32()
        {
            return (uint) PopU64();
        }


        internal void PushS32(int val)
        {
            PushU32((uint) val);
        }

        internal int PopS32()
        {
            return (int) PopU32();
        }

        internal void PushF32(float val)
        {
            var bytes = BitConverter.GetBytes(val);
            PushU32(BitConverter.ToUInt32(bytes));
        }

        internal float PopF32()
        {
            var bytes = BitConverter.GetBytes(PopU32());
            return BitConverter.ToSingle(bytes);
        }

        internal void PushF64(double val)
        {
            var bytes = BitConverter.GetBytes(val);
            PushU64(BitConverter.ToUInt64(bytes));
        }

        internal double PopF64()
        {
            var bytes = BitConverter.GetBytes(PopU64());
            return BitConverter.ToDouble(bytes);
        }

        internal void PushBool(bool val)
        {
            PushU64(val ? 1ul : 0ul);
        }

        internal bool PopBool()
        {
            return PopU64() != 0ul;
        }
    }
}